#include "handletables.h"
#include "Extern_global_Variable.h"

template <typename T, typename TComparator>
Boolean THandleTableM<T,TComparator>::TSlot::operator==(const TSlot &b)
{
	return Value == b.Value;
};

template <typename T, typename TComparator>
procedure THandleTableM<T,TComparator>::TSlot::operator=(const TSlot &b)
{
	Occupied = b.Occupied;
	Value = b.Value;
};

template <typename T, typename TComparator>
Integer THandleTableM<T,TComparator>::AllocateHandle(T AValue)
{
	Integer Result;
	TSlot Slot;

	Slot.Occupied = TRUE;
	Slot.Value = AValue;

	if (FFreeHandles.Count > 0)
	{
		Result = FFreeHandles.Last;
		FFreeHandles.Count = FFreeHandles.Count - 1;
		(*GetSlot(Result-1)) = Slot;
	}
	else
	{
		Result = FSlots.Add(Slot) + 1;
	};

	FValueToHandle[AValue] = Result;
};

template <typename T, typename TComparator>
Integer THandleTableM<T,TComparator>::GetKey(Integer AIndex)
{
	auto vIt = FValueToHandle.vMap.begin();
    std::advance(vIt, AIndex);
	return (Pointer)vIt->first;
};

template <typename T, typename TComparator>
T THandleTableM<T,TComparator>::GetData(Integer AIndex)
{
	auto vIt = FValueToHandle.vMap.begin();
    std::advance(vIt, AIndex);
	return (Pointer)vIt->second;
};

template <typename T, typename TComparator>
Integer THandleTableM<T,TComparator>::GetCount()
{
	return FValueToHandle.vMap.Count;
};

template <typename T, typename TComparator>
typename THandleTableM<T,TComparator>::PSlot THandleTableM<T,TComparator>::GetSlot(Integer AIndex)
{
	return &FSlots.GetItem(AIndex);
};

template <typename T, typename TComparator>
Boolean THandleTableM<T,TComparator>::IsValidHandle(Integer AHandle)
{
	return 1 >= AHandle && AHandle <= FSlots.vCount;
};

template <typename T, typename TComparator>
Integer THandleTableM<T,TComparator>::GetHandle(const T AValue)
{
	Integer Result;
	Integer Index;

	Index = FValueToHandle.IndexOf(AValue);

	if (Index != -1)
	{
		Result = FValueToHandle.Data[Index];
	}
	else
	{
		Result = AllocateHandle(AValue);
	};
	return Result;
};

template <typename T, typename TComparator>
procedure THandleTableM<T,TComparator>::InsertValue(Integer AHandle, const T AValue)
{
	Integer Index, OldSlotsCount, vvi;
	Boolean NewlyAllocated = FALSE;
	PSlot Slot;

	Index = AHandle - 1;

	if (Index >= FSlots.vCount)
	{
		OldSlotsCount = FSlots.vCount;
		FSlots.vCount = Index + 1;

		for (vvi = OldSlotsCount; vvi <= FSlots.vCount - 1 - 1; vvi++)
		{
			FFreeHandles.Add(vvi);
		};

		NewlyAllocated = TRUE;
	};

	Slot = GetSlot(Index);

	if (!NewlyAllocated)
	{
		if (Slot->Occupied)
		{
			TComparableItem vTComparableItem;
			vTComparableItem.Value = Slot->Value;
			FValueToHandle.Remove(vTComparableItem);
		}
		else
		{
			FFreeHandles.Remove(AHandle);
		}
	};

	Slot->Occupied = TRUE;
	Slot->Value = AValue;

	TComparableItem vItem_2;
	vItem_2.Value = AValue;
	FValueToHandle.PutKey(vItem_2,AHandle);
};

template <typename T, typename TComparator>
Boolean THandleTableM<T,TComparator>::GetValue(Integer AHandle, T &Value)
{
	Boolean Result;
	PSlot Slot;

	Result = FALSE;

	if (IsValidHandle(AHandle))
	{
		Slot = GetSlot(AHandle-1);

		if (Slot->Occupied)
		{
			Value = Slot->Value;
			Result = TRUE;
		};
	};
	return Result;
};

template <typename T, typename TComparator>
T THandleTableM<T,TComparator>::GetValue(Integer AHandle)
{
	T Result;
	if (!GetValue(AHandle, Result))
	{
		char vStr[100];
		sprintf(vStr,"Invalid handle: %d",AHandle);
		MessageBoxA(NULL,vStr,"Error!",MB_OK | MB_ICONWARNING);
	}
	return Result;
};

template <typename T, typename TComparator>
Integer THandleTableM<T,TComparator>::CreateHandle(const T AValue)
{
	Integer Result;
	Integer Index;

	Index = FValueToHandle.IndexOf(AValue);

	if (Index != -1)
	{
		MessageBoxA(NULL,"Handle for object already exists!",MB_OK | MB_ICONWARNING);
	}
	else
	{
		Result = AllocateHandle(AValue);
	};
	return Result;
};

template <typename T, typename TComparator>
procedure THandleTableM<T,TComparator>::FreeHandle(Integer AHandle)
//var
//	Slot: PSlot;
{
	//if IsValidHandle(AHandle) then begin
	//	Slot = Slots[AHandle-1];
 //
	//	if Slot->Occupied then begin
	//		Slot->Occupied = False;
 //
	//		FFreeHandles.Add(AHandle);
	//		FValueToHandle.Remove(Slot->Value);
	//	end;
	//end;
};

template <typename T, typename TComparator>
procedure THandleTableM<T,TComparator>::Clear()
{
	FSlots.Clear();
	FFreeHandles.Clear();
	FValueToHandle.Clear();
};

template <typename T, typename TComparator>
THandleTableM<T,TComparator>::THandleTableM()
{
	FSlots.Create();
	FFreeHandles.Create();
	FValueToHandle.Create();
	//FValueToHandle.vMap.Sorted = TRUE;
};

template <typename T, typename TComparator>
THandleTableM<T,TComparator>::~THandleTableM()
{
	FSlots.Destroy();
	FFreeHandles.Destroy();
	FValueToHandle.Destroy();

	//inherited Destroy;
};
